//
//  YSAlertAction.m
//  YSAlertActionExample
//
//  Created by Kyson on 2018/5/7.
//  Copyright © 2018年 YangShen. All rights reserved.
//

#import "YSAlertAction.h"
#import <objc/runtime.h>

//#pragma clang diagnostic push
// 不写push pop 整个类都取消这个警告
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
//写在这个中间的代码,都不会被编译器提示-Wincompatible-pointer-types类型的警告
//#pragma clang diagnostic pop

#pragma mark - Category
@interface UIWindow (YSAlertAction)
//获取当前显示
- (UIViewController*)currentTopViewController;
@end

@implementation UIWindow (YSAlertAction)

- (UIViewController*)topRootController {
    UIViewController *topController = [self rootViewController];
    
    //  Getting topMost ViewController
    while ([topController presentedViewController])    topController = [topController presentedViewController];
    
    //  Returning topMost ViewController
    return topController;
}

- (UIViewController*)currentTopViewController {
    UIViewController *currentTopViewController = [self topRootController];
    
    if ([currentTopViewController isKindOfClass:[UITabBarController class]]
        && ((UITabBarController*)currentTopViewController).selectedViewController != nil ) {
        currentTopViewController = ((UITabBarController*)currentTopViewController).selectedViewController;
    }
    
    while ([currentTopViewController isKindOfClass:[UINavigationController class]]
           && [(UINavigationController*)currentTopViewController topViewController]) {
        currentTopViewController = [(UINavigationController*)currentTopViewController topViewController];
    }
    
    return currentTopViewController;
}

@end

static char alertKey;
@interface UIAlertView (YSAlertAction)

// 用Block的方式回调，这时候会默认用self作为Delegate
- (void)showWithBlock:(void(^)(NSInteger buttonIndex)) block;

@end

@implementation UIAlertView (YSAlertAction)

- (void(^)(NSInteger buttonIndex))block {
    return objc_getAssociatedObject(self, &alertKey);;
}

- (void)setBlock:(void(^)(NSInteger buttonIndex))block {
    if (block) {
        objc_removeAssociatedObjects(self);
        objc_setAssociatedObject(self, &alertKey, block, OBJC_ASSOCIATION_COPY);
    }
}


- (void)showWithBlock:(void(^)(NSInteger buttonIndex))block {
    self.block = block;
    self.delegate = self;
    
    [self show];
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (self.block) {
        self.block(buttonIndex);
    }
    
    objc_removeAssociatedObjects(self); // 断开所有关联
}

@end

@interface UIAlertController (supportedInterfaceOrientations)

@end

@implementation UIAlertController (supportedInterfaceOrientations)
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000
- (NSUInteger)supportedInterfaceOrientations; {
    return UIInterfaceOrientationMaskPortrait;
}
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}
#endif
@end

static char actionSheetkey;
@interface UIActionSheet (YSAlertAction) <UIActionSheetDelegate>

- (void)showInView:(UIView *)view block:(void(^)(NSInteger idx,NSString* buttonTitle))block;

@end

#pragma mark - UIActionSheet
@implementation UIActionSheet (YSAlertAction)

- (void(^)(NSInteger idx,NSString* buttonTitle))block {
    return objc_getAssociatedObject(self, &actionSheetkey);;
}

- (void)setBlock:(void(^)(NSInteger idx,NSString* buttonTitle))block {
    if (block) {
        objc_setAssociatedObject(self, &actionSheetkey, block, OBJC_ASSOCIATION_COPY);
    }
}

- (void)showInView:(UIView *)view block:(void(^)(NSInteger idx,NSString* buttonTitle))block {
    self.block = block;
    
    self.delegate = self;
    [self showInView:view];
}


// Called when a button is clicked. The view will be automatically dismissed after this call returns
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (self.block) {
        self.block(buttonIndex,[self buttonTitleAtIndex:buttonIndex]);
    }
    
    objc_removeAssociatedObjects(self);
}

// Called when we cancel a view (eg. the user clicks the Home button). This is not called when the user clicks the cancel button.
// If not defined in the delegate, we simulate a click in the cancel button
- (void)actionSheetCancel:(UIActionSheet *)actionSheet {
    objc_removeAssociatedObjects(self);
}

@end

@implementation YSAlertAction

+ (void)showAlertWithTitle:(NSString *)title
                   message:(NSString *)message
              buttonTitles:(NSArray<NSString *> *)buttonTitles
          buttonIndexBlock:(void (^)(NSInteger))block {
    NSMutableArray *titlesArray = [[NSMutableArray alloc] initWithArray:buttonTitles];
    
    if ( [self isIosVersion8AndAfter]) {
        // UIAlertController
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
        for (int i = 0; i < [titlesArray count]; i++) {
            UIAlertActionStyle style = (0 == i) ? UIAlertActionStyleCancel : UIAlertActionStyleDefault;
            // Create the actions.
            UIAlertAction *action = [UIAlertAction actionWithTitle:[titlesArray objectAtIndex:i] style:style handler:^(UIAlertAction *action) {
                if (block) {
                    block(i);
                }
            }];
            [alertController addAction:action];
        }
        
        [[self getTopViewController] presentViewController:alertController animated:YES completion:nil];
        return;
    }
    
    // UIAlertView
    UIAlertView* alertView = [[UIAlertView alloc]initWithTitle:title message:message delegate:nil cancelButtonTitle:titlesArray[0] otherButtonTitles:nil, nil];
    
    [titlesArray removeObject:titlesArray[0]];
    for (NSString *buttonTitle in titlesArray) {
        NSLog(@"buttonTitle: %@", buttonTitle);
        [alertView addButtonWithTitle:buttonTitle];
    }
    
    [alertView showWithBlock:^(NSInteger buttonIdx) {
         if (block) {
             block(buttonIdx);
         }
     }];
}

+ (void)showActionSheetWithTitle:(NSString *)title
                         message:(NSString *)message
               cancelButtonTitle:(NSString *)cancelString
          destructiveButtonTitle:(NSString *)destructiveButtonTitle
               otherButtonTitles:(NSArray<NSString *> *)otherButtonArray
                buttonIndexBlock:(void (^)(NSInteger))block {
    NSMutableArray *titlesArray = [[NSMutableArray alloc] initWithCapacity:3];
    
    if (cancelString) {
        [titlesArray addObject:cancelString];
    }
    if (destructiveButtonTitle) {
        [titlesArray addObject:destructiveButtonTitle];
    }
    
    [titlesArray addObjectsFromArray:otherButtonArray];
    
    if ( [self isIosVersion8AndAfter]) {
        UIAlertController* alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleActionSheet];
        for (int i = 0; i < [titlesArray count]; i++) {
            UIAlertActionStyle style =  (0 == i) ? UIAlertActionStyleCancel : UIAlertActionStyleDefault;
            
            if (1==i && destructiveButtonTitle) {
                style = UIAlertActionStyleDestructive;
            }
            
            // Create the actions.
            UIAlertAction *action = [UIAlertAction actionWithTitle:[titlesArray objectAtIndex:i] style:style handler:^(UIAlertAction *action) {
                if (block) {
                    block(i);
                }
            }];
            [alertController addAction:action];
        }
        
        [[self getTopViewController] presentViewController:alertController animated:YES completion:nil];
        return;
    }
    
    // UIActionSheet
    UIView *view = [self getTopViewController].view;
    UIActionSheet *sheet = nil;
    
    NSInteger count = titlesArray.count;
    
    if (cancelString) {
        [titlesArray removeObject:cancelString];
    }
    if (destructiveButtonTitle) {
        [titlesArray removeObject:destructiveButtonTitle];
    }
    
    if (titlesArray.count == 0) {
        sheet =  [[UIActionSheet alloc]initWithTitle:title delegate:nil cancelButtonTitle:cancelString destructiveButtonTitle:destructiveButtonTitle otherButtonTitles:nil, nil];
    }
    
    switch (titlesArray.count) {
        case 0:
            sheet = [[UIActionSheet alloc]initWithTitle:title delegate:nil cancelButtonTitle:cancelString destructiveButtonTitle:destructiveButtonTitle otherButtonTitles:nil, nil];
            break;
            
        case 1:
            sheet = [[UIActionSheet alloc]initWithTitle:title delegate:nil cancelButtonTitle:cancelString destructiveButtonTitle:destructiveButtonTitle otherButtonTitles:titlesArray[0], nil];
            break;
            
        case 2:
            sheet = [[UIActionSheet alloc]initWithTitle:title delegate:nil cancelButtonTitle:cancelString destructiveButtonTitle:destructiveButtonTitle otherButtonTitles:titlesArray[0],titlesArray[1], nil];
            break;
        case 3:
            sheet = [[UIActionSheet alloc]initWithTitle:title delegate:nil cancelButtonTitle:cancelString destructiveButtonTitle:destructiveButtonTitle otherButtonTitles:titlesArray[0],titlesArray[1],titlesArray[2], nil];
            break;
            
        case 4:
            sheet = [[UIActionSheet alloc]initWithTitle:title delegate:nil cancelButtonTitle:cancelString destructiveButtonTitle:destructiveButtonTitle otherButtonTitles:titlesArray[0],titlesArray[1],titlesArray[2],titlesArray[3], nil];
            break;
            
        case 5:
            sheet = [[UIActionSheet alloc]initWithTitle:title delegate:nil cancelButtonTitle:cancelString destructiveButtonTitle:destructiveButtonTitle otherButtonTitles:titlesArray[0],titlesArray[1],titlesArray[2],titlesArray[3],titlesArray[4], nil];
            break;
            
        case 6:
            sheet = [[UIActionSheet alloc]initWithTitle:title delegate:nil cancelButtonTitle:cancelString destructiveButtonTitle:destructiveButtonTitle otherButtonTitles:titlesArray[0],titlesArray[1],titlesArray[2],titlesArray[3],titlesArray[4],titlesArray[5], nil];
            break;
            
        case 7:
            sheet = [[UIActionSheet alloc]initWithTitle:title delegate:nil cancelButtonTitle:cancelString destructiveButtonTitle:destructiveButtonTitle otherButtonTitles:titlesArray[0],titlesArray[1],titlesArray[2],titlesArray[3],titlesArray[4],titlesArray[5],titlesArray[6], nil];
            break;
            
        case 8:
            sheet = [[UIActionSheet alloc]initWithTitle:title delegate:nil cancelButtonTitle:cancelString destructiveButtonTitle:destructiveButtonTitle otherButtonTitles:titlesArray[0],titlesArray[1],titlesArray[2],titlesArray[3],titlesArray[4],titlesArray[5],titlesArray[6],titlesArray[7], nil];
            break;
            
        default:
            break;
    }
    
    [sheet showInView:view block:^(NSInteger buttonIdx,NSString* buttonTitle) {
         NSInteger idx = buttonIdx;
         if (idx == count - 1) {
             idx = 0;
         } else {
             ++idx;
         }
         
         NSLog(@"idx: %ld",idx);
         
         if (block) {
             block(idx);
         }
     }];
    
}

#pragma mark - Helper
+ (BOOL)isIosVersion8AndAfter {
    return [[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0 ;
}

+ (UIViewController*)getTopViewController {
    UIWindow * window = [[UIApplication sharedApplication] keyWindow];
    return window.currentTopViewController;
}

@end
